package ua.org.enginer.controls {
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextLineMetrics;
	
	import mx.binding.utils.ChangeWatcher;
	import mx.controls.Button;
	import mx.controls.LinkButton;
	import mx.controls.TextInput;
	import mx.core.ClassFactory;
	import mx.core.IDataRenderer;
	import mx.core.IFactory;
	import mx.core.UIComponent;
	import mx.core.UITextField;
	import mx.events.FlexEvent;
	
	//use namespace mx_internal;
	
	//[Event(name="change", type="mx.events.Event")]
	
	/**
	 *  Name of the class to use as the edit icon. 
	 *  
	 *  @default ua/org/enginer/assets/icons/pencil.png 
	 */
	[Style(name="editIcon", type="Class", inherit="no")]
	
	/**
	 *  Name of the class to use as the commit icon. 
	 *  
	 *  @default ua/org/enginer/assets/icons/tick_circle_frame.png 
	 */
	[Style(name="commitIcon", type="Class", inherit="no")]
	
	/**
	 *  Name of the class to use as the commit icon. 
	 *  
	 *  @default ua/org/enginer/assets/icons/tick_circle_frame.png 
	 */
	[Style(name="canselIcon", type="Class", inherit="no")]
	
	//include "../styles/TextStyles.as"
	/**
	 *  Color of text in the component, including the component label.
	 *
	 *  @default 0x0B333C
	 */
	[Style(name="color", type="uint", format="Color", inherit="yes")]
	
	/**
	 *  Color of text in the component if it is disabled.
	 *
	 *  @default 0xAAB3B3
	 */
	[Style(name="disabledColor", type="uint", format="Color", inherit="yes")]
	
	/**
	 *  Sets the <code>antiAliasType</code> property of internal TextFields. The possible values are 
	 *  <code>"normal"</code> (<code>flash.text.AntiAliasType.NORMAL</code>) 
	 *  and <code>"advanced"</code> (<code>flash.text.AntiAliasType.ADVANCED</code>). 
	 *  
	 *  <p>The default value is <code>"advanced"</code>, which enables advanced anti-aliasing for the font.
	 *  Set to <code>"normal"</code> to disable the advanced anti-aliasing.</p>
	 *  
	 *  <p>This style has no effect for system fonts.</p>
	 *  
	 *  <p>This style applies to all the text in a TextField subcontrol; 
	 *  you cannot apply it to some characters and not others.</p>
	 
	 *  @default "advanced"
	 * 
	 *  @see flash.text.TextField
	 *  @see flash.text.AntiAliasType
	 */
	[Style(name="fontAntiAliasType", type="String", enumeration="normal,advanced", inherit="yes")]
	
	/**
	 *  Name of the font to use.
	 *  Unlike in a full CSS implementation,
	 *  comma-separated lists are not supported.
	 *  You can use any font family name.
	 *  If you specify a generic font name,
	 *  it is converted to an appropriate device font.
	 * 
	 *  @default "Verdana"
	 */
	[Style(name="fontFamily", type="String", inherit="yes")]
	
	/**
	 *  Sets the <code>gridFitType</code> property of internal TextFields that represent text in Flex controls.
	 *  The possible values are <code>"none"</code> (<code>flash.text.GridFitType.NONE</code>), 
	 *  <code>"pixel"</code> (<code>flash.text.GridFitType.PIXEL</code>),
	 *  and <code>"subpixel"</code> (<code>flash.text.GridFitType.SUBPIXEL</code>). 
	 *  
	 *  <p>This property only applies when you are using an embedded font 
	 *  and the <code>fontAntiAliasType</code> property 
	 *  is set to <code>"advanced"</code>.</p>
	 *  
	 *  <p>This style has no effect for system fonts.</p>
	 * 
	 *  <p>This style applies to all the text in a TextField subcontrol; 
	 *  you can't apply it to some characters and not others.</p>
	 * 
	 *  @default "pixel"
	 *  
	 *  @see flash.text.TextField
	 *  @see flash.text.GridFitType
	 */
	[Style(name="fontGridFitType", type="String", enumeration="none,pixel,subpixel", inherit="yes")]
	
	/**
	 *  Sets the <code>sharpness</code> property of internal TextFields that represent text in Flex controls.
	 *  This property specifies the sharpness of the glyph edges. The possible values are Numbers 
	 *  from -400 through 400. 
	 *  
	 *  <p>This property only applies when you are using an embedded font 
	 *  and the <code>fontAntiAliasType</code> property 
	 *  is set to <code>"advanced"</code>.</p>
	 *  
	 *  <p>This style has no effect for system fonts.</p>
	 * 
	 *  <p>This style applies to all the text in a TextField subcontrol; 
	 *  you can't apply it to some characters and not others.</p>
	 *  
	 *  @default 0
	 *  
	 *  @see flash.text.TextField
	 */
	[Style(name="fontSharpness", type="Number", inherit="yes")]
	
	/**
	 *  Height of the text, in pixels.
	 *
	 *  The default value is 10 for all controls except the ColorPicker control. 
	 *  For the ColorPicker control, the default value is 11. 
	 */
	[Style(name="fontSize", type="Number", format="Length", inherit="yes")]
	
	/**
	 *  Determines whether the text is italic font.
	 *  Recognized values are <code>"normal"</code> and <code>"italic"</code>.
	 * 
	 *  @default "normal"
	 */
	[Style(name="fontStyle", type="String", enumeration="normal,italic", inherit="yes")]
	
	/**
	 *  Sets the <code>thickness</code> property of internal TextFields that represent text in Flex controls.
	 *  This property specifies the thickness of the glyph edges.
	 *  The possible values are Numbers from -200 to 200. 
	 *  
	 *  <p>This property only applies when you are using an embedded font 
	 *  and the <code>fontAntiAliasType</code> property 
	 *  is set to <code>"advanced"</code>.</p>
	 *  
	 *  <p>This style has no effect on system fonts.</p>
	 * 
	 *  <p>This style applies to all the text in a TextField subcontrol; 
	 *  you can't apply it to some characters and not others.</p>
	 *  
	 *  @default 0
	 *  
	 *  @see flash.text.TextField
	 */
	[Style(name="fontThickness", type="Number", inherit="yes")]
	
	/**
	 *  Determines whether the text is boldface.
	 *  Recognized values are <code>normal</code> and <code>bold</code>.
	 *  The default value for Button controls is <code>bold</code>. 
	 *  The default value for all other controls is <code>normal</code>.
	 */
	[Style(name="fontWeight", type="String", enumeration="normal,bold", inherit="yes")]
	
	/**
	 *  A Boolean value that indicates whether kerning
	 *  is enabled (<code>true</code>) or disabled (<code>false</code>).
	 *  Kerning adjusts the gap between certain character pairs
	 *  to improve readability, and should be used only when necessary,
	 *  such as with headings in large fonts.
	 *  Kerning is supported for embedded fonts only. 
	 *  Certain fonts, such as Verdana, and monospaced fonts,
	 *  such as Courier New, do not support kerning.
	 *
	 *  @default false
	 */
	[Style(name="kerning", type="Boolean", inherit="yes")]
	
	/**
	 *  The number of additional pixels to appear between each character.
	 *  A positive value increases the character spacing beyond the normal spacing,
	 *  while a negative value decreases it.
	 * 
	 *  @default 0
	 */
	[Style(name="letterSpacing", type="Number", inherit="yes")]
	
	/**
	 *  Alignment of text within a container.
	 *  Possible values are <code>"left"</code>, <code>"right"</code>,
	 *  or <code>"center"</code>.
	 * 
	 *  <p>The default value for most components is <code>"left"</code>.
	 *  For the FormItem component,
	 *  the default value is <code>"right"</code>.
	 *  For the Button, LinkButton, and AccordionHeader components,
	 *  the default value is <code>"center"</code>, and
	 *  this property is only recognized when the
	 *  <code>labelPlacement</code> property is set to <code>"left"</code> or
	 *  <code>"right"</code>.
	 *  If <code>labelPlacement</code> is set to <code>"top"</code> or
	 *  <code>"bottom"</code>, the text and any icon are centered.</p>
	 */
	[Style(name="textAlign", type="String", enumeration="left,center,right", inherit="yes")]
	
	/**
	 *  Determines whether the text is underlined.
	 *  Possible values are <code>"none"</code> and <code>"underline"</code>.
	 * 
	 *  @default "none"
	 */
	[Style(name="textDecoration", type="String", enumeration="none,underline", inherit="yes")]
	
	/**
	 *  Offset of first line of text from the left side of the container, in pixels.
	 * 
	 *  @default 0
	 */
	[Style(name="textIndent", type="Number", format="Length", inherit="yes")]
	
	[DefaultProperty(name="editor")]
	
	public class EditableLabel extends UIComponent implements IDataRenderer {
		
		[Embed(source="ua/org/enginer/assets/icons/pencil.png")]
		private var defaultEditIcon:Class
		/*[Embed(source="ua/org/enginer/assets/icons/tick_circle_frame.png")]
		private var defaultCommitIcon:Class
		[Embed(source="ua/org/enginer/assets/icons/cross.png")]
		private var defaultCanselIcon:Class
		*/
		
		private var icon:DisplayObject
		private var mainButton:Button
		private var canselButton:Button
		private var renderer:UITextField
		//private var editor:UIComponent
		
		public function EditableLabel() {
			super();
			addEventListener(MouseEvent.CLICK, onClick)
		}
		
		protected function onClick(event:MouseEvent):void {
			if (editable && !editMode) editMode = true
		}
		
		private var _text:String = null;
		private var _textChanged:Boolean
		public function set text(value:String):void {
			_text = value;
			_textChanged = true
			invalidateProperties()
			invalidateSize()
		}
		
		public function get text():String {
			if (_text) return _text
			if (data is String) return String(data)
			if (data is Object) return data[dataField]
			return ''
		}
		
		private var _prompt:String = "";
		private var _promptChanged:Boolean
		public function get prompt():String {
			return _prompt;
		}
		
		//[Bindable]
		public function set prompt(value:String):void	{
			_prompt = value;
			_promptChanged = true
			invalidateProperties();
			//invalidateDisplayList();
		}
		
		private var _promptFormat:String = '<font color="#999999"><i>[prompt]</i></font>';
		
		/** 
		 * A format string to specify how the prompt is displayed.  This is typically
		 * an HTML string that can set the font color and style.  Use <code>[prompt]</code>
		 * within the string as a replacement token that will be replaced with the actual
		 * prompt text.
		 * 
		 * The default value is "&lt;font color="#999999"&gt;&lt;i&gt;[prompt]&lt;/i&gt;&lt;/font&gt;"
		 */
		public function get promptFormat():String {
			return _promptFormat;
		}
		
		public function set promptFormat(value:String):void	{
			_promptFormat = value;
			// Check to see if the replacement code is found in the new format string
			if ( _promptFormat.indexOf( "[prompt]" ) < 0 )	{
				// TODO: Log error with the logging framework, or just use trace?
				//trace( "PromptingTextInput warning: prompt format does not contain [prompt] replacement code." );	
			}
			
			invalidateProperties()
		}
		
		private var _editable:Boolean;
		public function set editable(value:Boolean):void {
			_editable = value;
			invalidateProperties()
		}
		
		public function get editable():Boolean {
			return _editable;
		}
		
		private var _editMode:Boolean
		public function set editMode(value:Boolean):void {
			_editMode = value
			invalidateProperties()
		} 
		[Bindable]
		public function get editMode():Boolean {
			return _editMode
		}
		
		private var _editorRenderer:IFactory;
		private var _editorRendererChanged:Boolean
		public function set editorRenderer(value:IFactory):void {
			_editorRenderer = value;
			_editorRendererChanged = true
			invalidateProperties()
		}
		
		public function get editorRenderer():IFactory {
			return _editorRenderer;
		}
		
		private var _editor:DisplayObject;
		public function set editor(value:DisplayObject):void {
			_editor = value;
			invalidateProperties()
		}
		
		public function get editor():DisplayObject {
			return _editor;
		}
		
		private var _dataField:String = "label"
		private var _dataFieldChanged:Boolean
		public function set dataField(value:String):void {
			_dataField = value;
			invalidateProperties()
		}
		
		public function get dataField():String {
			return _dataField;
		}
		
		/**
		 *  The name of the property of the item editor that contains the new
		 *  data for the list item.
		 *  For example, the default <code>editor</code> is
		 *  TextInput, so the default value of the <code>editorDataField</code> 
		 *  property is <code>"text"</code>, which specifies the 
		 *  <code>text</code> property of the TextInput control.
		 *
		 *  @default "text"
		 */
		private var _editorDataField:String;
		public function set editorDataField(value:String):void {
			_editorDataField = value;
		}
		
		public function get editorDataField():String {
			return _editorDataField
		}
		
		//public var preventChangeByEditor:Boolean
		
		override protected function createChildren():void {
			super.createChildren()
			
			renderer = new UITextField()
			renderer.text = text
			renderer.selectable = true
			renderer.styleName = this
			addChild(renderer)
			
			mainButton = new LinkButton()
			canselButton = new LinkButton()
		}
		
		override protected function commitProperties():void {
			super.commitProperties()
			
			if (_dataFieldChanged || _dataChanged || _promptChanged || _textChanged)  {
				if (prompt && !text) {
					renderer.htmlText = promptFormat.replace(/\[prompt\]/g, prompt)
				}else 
					renderer.text = text
				
				if(_editor) {
					//if (_editor.hasOwnProperty('text')) _editor['text'] = ''
					//if (owns(_editor)) removeChild(_editor)
					//_editor = null
				}
				
				_dataChanged = false
				_textChanged = false
				_dataFieldChanged = false
				_promptChanged = false
				//editMode = false
			}
			
			editMode = editMode && editable
			renderer.visible = !editMode
			
			if (editable && editMode) {
				if ((!editor && editorRenderer) || _editorRendererChanged) {
					editor = editorRenderer.newInstance()
					_editorRendererChanged = false
				}
				if (!editor) editor = new ClassFactory(TextInput).newInstance()
				
				IDataRenderer(editor).data = text
				
				editor.addEventListener(Event.CHANGE, onChange)
				
				addChild(editor)
				invalidateSize()
			}
			else if (!editable || !editMode) {
				if (editor && owns(editor)) removeChild(editor)
			}
			
			// icon
			if (editable) {
				//icon = getIcon()
				
				//button.label = "edit"
				//button.useHandCursor = true
				//button.mouseEnabled = false
				//button.mouseChildren = true
				//button.styleName = new StyleProxy(this, null)
				//button.setStyle("icon", getIcon())
				mainButton.setStyle("icon", getIcon())
				mainButton.toolTip = "edit"
				if (!owns(mainButton)) {
					addChild(mainButton)
					mainButton.addEventListener(FlexEvent.BUTTON_DOWN, editButtonDownHandler)
					mainButton.invalidateDisplayList();
				}
				
				/*
				if (!owns(canselButton)) {
				var icon:Class = getStyle("canselIcon")
				canselButton.setStyle("icon", icon ? icon : defaultCanselIcon)
				addChild(canselButton)
				canselButton.addEventListener(FlexEvent.BUTTON_DOWN, canselButtonDownHandler)
				canselButton.invalidateDisplayList();
				}
				*/
			}
			if ((!editable || (editable && editMode)) && mainButton && owns(mainButton)) {
				removeChild(mainButton)
			}
			/*
			if (!editMode && canselButton && owns(canselButton)) {
			removeChild(canselButton)
			}
			*/
			invalidateSize()
		}
		
		override protected function measure():void {
			super.measure()
			
			var textWidth:Number = 0;
			var textHeight:Number = 0;
			
			if (renderer.text) {
				var lineMetrics:TextLineMetrics = measureText(renderer.text);
				textWidth = lineMetrics.width + 4;
				textHeight = lineMetrics.height + 3;
			}
			
			renderer.width = textWidth
			renderer.height = textHeight
			renderer.y = 2
			
			var iconWidth:Number = 22;
			var iconHeight:Number = 22;
			
			
			
			var w:Number = textWidth
			var h:Number = textHeight
			/*
			if (editMode) {
			w = Math.max(w, editorInst.measuredWidth)
			h = Math.max(h, editorInst.height)
			}*/
			
			if (editMode) {
				w = Math.max(textWidth + 10, UIComponent.DEFAULT_MEASURED_WIDTH);
				h = Math.max(textHeight + 5, UIComponent.DEFAULT_MEASURED_HEIGHT);
				editor.width = w
				editor.height = h
				
				iconWidth = iconHeight = 0
			}
			
			if (owns(mainButton)) {
				mainButton.setActualSize(iconWidth, iconHeight)
				mainButton.move(w, 0)
			}
			
			if (owns(canselButton)) {
				canselButton.setActualSize(iconWidth, iconHeight)
				canselButton.move(w+iconWidth, 0)
				w += iconWidth
			}
			
			measuredMinWidth = measuredWidth = w + iconWidth
			measuredMinHeight = measuredHeight = Math.max(h, iconHeight)
		}
		
		
		protected function getIcon():Class {
			var icon:Class
			
			if (!editMode) {
				icon = getStyle("editIcon")
				icon = icon ? icon : defaultEditIcon
			}else {
				icon = getStyle("commitIcon")
				icon = icon //? icon : defaultCommitIcon
			}
			
			return icon
		}
		
		private function editButtonDownHandler(event:FlexEvent):void {
			//if (editable && !editMode) 
			editMode = true
			//else 
			//if (editable && !preventChangeByEditor) 
			//commitEditorData()
		}
		/*
		private function canselButtonDownHandler(event:FlexEvent):void {
		editMode = false
		}
		*/
		//*
		public var commitDataFunction:Function
		
		protected function commitEditorData():void {
			if (!commitDataFunction) {
				if (data is String || !data) data = editorDataField ? editor[editorDataField] : editor['text']
				else if (data is Object) data[dataField] = editorDataField ? editor[editorDataField] : editor['text']
			}else {
				commitDataFunction(editor)
			}
			//text = 
			//editMode = false
			//var event:Event = new Event(Event.CHANGE)
			//event.currentTarget = editorInst
			//dispatchEvent(event)
		}
		//*/
		
		override public function styleChanged(styleProp:String):void {
			if (mainButton)
				mainButton.styleChanged(styleProp);
			
			super.styleChanged(styleProp);
		}
		
		
		private var _data:Object;
		private var _dataChanged:Boolean;
		public function set data(value:Object):void {
			_data = value;
			_dataChanged = true
			ChangeWatcher.watch(_data, dataField, onDataChange)
			editMode = false
			invalidateProperties()
		}
		
		public function get data():Object {
			return _data;
		}
		
		protected function onDataChange(event:Event):void {
			//trace("d")
			//if (!editMode) {
			_dataChanged = true
			invalidateProperties()
			//}
		}	
		
		protected function onChange(event:Event):void {
			commitEditorData()
		}
	}
}

